package com.tjetc;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class _8SellingTicketsSolve {

    public static void main(String[] args) {

        // 注意start方法只能调用一次
        SellTicket sellTicket = new SellTicket();
        sellTicket.start();
        SellTicket sellTicket1 = new SellTicket();
        sellTicket1.start();
        SellTicket sellTicket2 = new SellTicket();
        sellTicket2.start();

        /*
            线程的同步：synchronized
            1. 同步代码块
                基本语法：
                    //得到对象的锁，才能操作同步代码
                    synchronized(对象){
                        //需要被同步代码；
                    }
            2. 同步方法
                基本语法：
                // synchronized还可以放在⽅法声明中，表示整个⽅法-为同步⽅法
                public synchronized void m (String name){
                    //需要被同步的代码
                }
         */

    }
}

@SuppressWarnings("all")
// 多线程会出现问题 数据共享：同时操作同一份数据
class SellTicket extends Thread {
    public static int ticketNum = 10;

    static boolean loop = true;
    boolean loop1 = true;
    // 创建🔒对象
    static Lock lock = new ReentrantLock();

    @Override
    public void run() {
//        while (loop) {
        while (loop1) {
            // 演示的是同步方法
//            sell();

            // 演示的是同步代码块
//            sell1();

            sell2();
        }
    }

    /*
        使用同步方法实现
            发现依旧是出现超卖现象，原因：
                1.因为sell是实例方法 所以每一个线程对象都会有一个sell方法
                2.synchronized 如果放在了实例方法中 相当于🔒的是this（当前对象）
            解决：
                将synchronized 放在静态方中 synchronized相当于锁的SellTicket.class

     */
//    public synchronized void sell(){
    public static synchronized void sell() {
        // 判断票是否卖完
        if (ticketNum <= 0) {
            System.out.println("卖完了");
            loop = false;
            return;
        }

        // 模拟买票的过程
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        ticketNum--;
        // 查看当前剩余票数
        System.out.println(Thread.currentThread().getName() + "剩余：" + ticketNum);
    }

    /*
        使用同步代码块实现

     */


    public void sell1() {
        // 有两种：1. 当前对象 2. 类对象 Class
//        synchronized (this) {
        synchronized (SellTicket.class) {
            // 判断票是否卖完
            if (ticketNum <= 0) {
                System.out.println("卖完了");
                loop1 = false;
                return;
            }

            // 模拟买票的过程
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            ticketNum--;
            // 查看当前剩余票数
            System.out.println(Thread.currentThread().getName() + "剩余：" + ticketNum);
        }

    }

    public void sell2() {
        // 上🔒
        lock.lock();
        try {
            // 判断票是否卖完
            if (ticketNum <= 0) {
                System.out.println("卖完了");
                loop1 = false;
                return;
            }

            // 模拟买票的过程
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            ticketNum--;
            // 查看当前剩余票数
            System.out.println(Thread.currentThread().getName() + "剩余：" + ticketNum);
        } finally {
            // 防止在代码中出现异常导致🔒未释放 一定要释放🔒
            lock.unlock();
        }
    }
}



